package com.gill.demo;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.util.List;

/**
 * curator监听子节点的增删改的demo演示
 */
public class CuratorZnodeWatcherChild {

    public CuratorFramework client;
    public static final String zkServerPath = "env:2181";

    /**
     * 实例化zk客户端
     */
    public CuratorZnodeWatcherChild() {
        /**
         * curator连接zookeeper的策略:RetryNTimes（本次案例采用该连接策略）
         * n：重试的次数
         * sleepMsBetweenRetries：每次重试间隔的时间
         */
        RetryPolicy retryPolicy = new RetryNTimes(3, 5000);

        client = CuratorFrameworkFactory.builder()
                .connectString(zkServerPath)
                .sessionTimeoutMs(10000)
                .retryPolicy(retryPolicy)
                .namespace("workspace")
                .build();

        // 连接zk服务端
        client.start();

    }

    /**
     *
     * @Description: 关闭zk客户端连接
     */
    public void closeZKClient() {
        if (client != null) {
            this.client.close();
        }
    }

    public static void main(String[] args) throws Exception {
        // 连接zk服务端，创建zk客户端实例
        CuratorZnodeWatcherChild curator = new CuratorZnodeWatcherChild();
        boolean isZkCuratorStarted = curator.client.isStarted();
        System.out.println("当前客户的状态：" + (isZkCuratorStarted ? "连接中" : "已关闭"));

        // 监听子节点（到zk服务端创建多个子节点，方便测试）
        String nodePath = "/super/imooc";
        String childNodePathCache =  nodePath;
        /**
         * PathChildrenCache: 监听数据节点子节点的增删改，会触发事件
         * cacheData: 是否缓存节点的数据
         */
        final PathChildrenCache childrenCache = new PathChildrenCache(curator.client, childNodePathCache, true);
        /**
         * StartMode: 初始化方式
         * POST_INITIALIZED_EVENT：异步初始化（推荐：初始化之后会触发事件）
         * NORMAL：异步初始化（不推荐：初始化之后不会触发任何时间，zk客户端不会收到任何通知）
         * BUILD_INITIAL_CACHE：同步初始化
         */
        childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);//使用该初始化方式会触发事件（推荐）

        List<ChildData> childDataList = childrenCache.getCurrentData();
        System.out.println("当前数据节点的子节点数据列表：");//注意，不是子节点，而是子节点的数据
        System.out.println(childDataList);

        childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
                    System.out.println("子节点初始化ok...");
                }
                else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
                    System.out.println("添加子节点:" + event.getData().getPath());
                    System.out.println("子节点数据:" + new String(event.getData().getData()));
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
                    System.out.println("删除子节点:" + event.getData().getPath());
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("修改子节点路径:" + event.getData().getPath());
                    System.out.println("修改子节点数据:" + new String(event.getData().getData()));
                }
            }
        });

        // 阻塞main线程，到zk服务端修改节点值，查看是否触发
        System.in.read();
    }

    private static class MyCuratorWatcher implements CuratorWatcher {
        @Override
        public void process(WatchedEvent watchedEvent) throws Exception {
            System.out.println("触发watcher，节点路径为：" + watchedEvent.getPath());
        }
    }

    private static class MyWatcher implements Watcher {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("触发watcher，节点路径为：" + event.getPath());
        }
    }
}
